<template>
    <el-upload
        ref="uploadFileRef"
        action=""
        :accept="uploadInfo.accept"
        :multiple="multiple"
        :show-file-list="false"
        :before-upload="onBeforeUpload"
        :http-request="onUploadFile">
        <template #default>
            <el-button id="localUpload" v-loading="uploadLoading" :disabled="props.disabled" class="local-button" plain>
                本地上传
            </el-button>
        </template>
    </el-upload>
    <el-dialog v-model="zipImgShow" class="upLoad-zip-img" width="400px" destroy-on-close>
        <template #header>
            <div class="dialog-header">提示！</div>
        </template>
        <div class="upLoad-zip-img-desc">
            您上传的图片大小或者尺寸已经超过了最大限制！如果继续，图片将会自动压缩处理。但请注意，压缩后的图片会影响图片的清晰度，请知晓！
        </div>
        <template #footer>
            <el-button @click="onChangeOne">换一张</el-button>
            <el-button v-loading="zipImgInfo.loading" class="right-button" type="primary" @click="onContinue">
                继续
            </el-button>
        </template>
    </el-dialog>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus';
import { ref, reactive, computed, withDefaults, getCurrentInstance } from 'vue';
import { getImageWH } from '../../utils/index';
import { uploadFileApi } from '../../api/material';
import jsImageCompressor from 'js-image-compressor';

interface Props {
    /**
     * 1-图片
     * 2-视频
     * 4-音频
     * 5-文件
     */
    type: number;
    /** 是否禁用 */
    disabled: boolean;
    /** 场景值 */
    sceneValue?: string;
}

const props = withDefaults(defineProps<Props>(), {
    type: 1,
    disabled: false,
    sceneValue: ''
});

const emit = defineEmits(['submit']);

/**
 * 当前上传配置信息
 */
const uploadInfo = computed(() => {
    return acceptFileList.find((el: any) => el.type == props.type) || {};
});

const app = getCurrentInstance();

const uploadLoading = ref<boolean>(false);

const uploadFileRef = ref<any>('');

const zipImgShow = ref<boolean>(false);

const zipImgInfo = reactive<any>({
    loading: false,
    file: 0,
    width: 0,
    height: 0
});

const acceptFileList = reactive<any>([
    {
        type: 1,
        accept: '.jpg,.JPG,.jpeg,.JPEG,.png,.PNG',
        size: 2
    },
    {
        type: 2,
        accept: '.mp4',
        size: 10
    },
    {
        type: 4,
        accept: '.mp3,.wma,.wav,.amr,.m4a',
        size: 200
    },
    {
        type: 5,
        accept: '.doc,.DOC,.docx,.DOCX,.xls,.XLS,.xlsx,.XLSX,.csv,.CSV,.ppt,.PPT,.pptx,.PPTX,.txt,.TXT,.pdf.PDF,.xmid,.Xmind',
        size: 10
    }
]);

const multiple = ref<boolean>(false);

const limitNum = ref('');

/**
 * 文件上传之前处理
 */
const onBeforeUpload = async (file: any) => {
    const { type, size, accept } = uploadInfo.value;
    const isMB = file.size / 1024 / 1024 <= size;

    // 图片
    if (type == 1) {
        zipImgInfo.file = file;
        const { W, H }: any = await getImageWH(file);
        zipImgInfo.width = W || 0;
        zipImgInfo.height = H || 0;
        if (!isMB) {
            zipImgShow.value = true;
            return false;
        }
        if (W * H > 1555200) {
            zipImgShow.value = true;
            return false;
        }
        if (H > 10800) {
            zipImgShow.value = true;
            return false;
        }
    }
    if (!isMB) {
        ElMessage.warning(`上传的文件最大支持${size}M`);
        return false;
    }
    const fileType = file?.name?.substring(file?.name?.lastIndexOf('.'));
    if (accept.indexOf(fileType) == -1) {
        ElMessage.error(`文件格式不正确，请上传${accept}格式文件！`);
        return false;
    }

    // 视频
    if (type == 2) {
        const vTime: any = await getVideoTimes(file);
        if (vTime > 30) {
            ElMessage.error('上传的视频不能超过30s');
            return false;
        }
    }
    return true;
};

/**
 * 文件上传
 */
const onUploadFile = async ({ file }: any) => {
    uploadLoading.value = true;
    const params = {
        file: file,
        fileName: file.name
    };
    const res = await uploadFileApi(app, params);

    emit('submit', { ...res, sortTime: +new Date() });
    uploadLoading.value = false;
};

/**
 * 压缩文件上传
 */
const onCompressUploadFile = async (file: any) => {
    uploadLoading.value = true;
    const params = {
        file: file,
        fileName: file.name
    };
    const res = await uploadFileApi(app, params);

    emit('submit', { ...res, sortTime: +new Date() });
    uploadLoading.value = false;
};

/**
 * 压缩图片
 */
const onImgCompress = () => {
    const file = zipImgInfo.file;
    const fileMb = file.size / 1024 / 1024;
    const imgRatio = 1 - uploadInfo.value.size / fileMb;
    const quality = getImgRatio(imgRatio);
    if (!quality) {
        ElMessage.warning(`上传的图片太大，无法压缩`);
        return;
    }
    if (!file) return;

    zipImgInfo.loading = true;
    const options: any = {
        file: file,
        quality: quality,
        success: async (res: any) => {
            const resFile = new File([res], res.name);
            await onCompressUploadFile(resFile);
            zipImgInfo.loading = false;
        }
    };
    if (props.sceneValue == 'friend') {
        if (1400 / zipImgInfo.width < 1) {
            options.maxWidth = zipImgInfo.width * (1400 / zipImgInfo.width);
        }
        if (1080 / zipImgInfo.height < 1) {
            options.maxHeight = zipImgInfo.height * (1080 / zipImgInfo.height);
        }
    }
    new jsImageCompressor(options);
};

/**
 * 获取图片压缩比
 */
const getImgRatio = (val?: any) => {
    if (val <= 0) {
        return 0.9;
    } else if (val <= 0.46) {
        return 0.8;
    } else if (val <= 0.67) {
        return 0.6;
    } else if (val <= 0.76) {
        return 0.4;
    } else if (val <= 0.83) {
        return 0.2;
    } else {
        return false;
    }
};

/**
 * 获取视频时长
 * @param file 文件
 */
const getVideoTimes = async (file: any) => {
    return new Promise((resolve, reject) => {
        const reader: any = new FileReader();
        reader.onload = () => {
            const videoDom = document.createElement('video');
            videoDom.setAttribute('src', reader.result);
            videoDom.oncanplay = () => {
                resolve(videoDom.duration);
            };
            videoDom.onerror = e => {
                reject(e);
            };
        };
        reader.readAsDataURL(file);
    });
};

/**
 * 换一张
 */
const onChangeOne = () => {
    const e = document.createEvent('MouseEvents');
    e.initEvent('click', true, true);
    document.getElementById('localUpload')?.dispatchEvent(e);
};

/**
 * 继续压缩
 */
const onContinue = () => {
    onImgCompress();
};
</script>
<style lang="scss" scoped>
.local-button {
    margin-right: 12px;
}

.upLoad-zip-img {
    .dialog-header {
        text-align: left;
    }

    .upLoad-zip-img-desc {
        padding: 24px 30px;
        line-height: 26px;
        text-align: left;
    }
}
</style>
